<?php defined('SYSPATH') OR die('No direct script access.');

class Controller_Publish extends Controller_Base {

	private $_config = array();

	public function before()
	{
		parent::before();
		$this->model['publish'] = Model::instance('publish');

		$this->_config = Kohana::$config->load('publish');
	}

	private function encode_signature($appid, $secret, $data = NULL)
	{
		$nonce = rand(100000,999999);
		$timestamp = local_to_utc(); //返回UTC，并且在客户端校验时间
		$signature = (new Encrypt($secret, MCRYPT_MODE_NOFB, MCRYPT_RIJNDAEL_128))->encode(serialize(compact('appid', 'nonce', 'data', 'timestamp')));
		return compact('signature','nonce');
	}

	private function verify_signature($secret, $signature, $nonce)
	{
		if (empty($this->_config['enabled']))
			return $this->failure('publish.failure_enabled');
		$_data = unserialize((new Encrypt($secret, MCRYPT_MODE_NOFB, MCRYPT_RIJNDAEL_128))->decode($signature));
		if (empty($_data) || $_data['nonce'] != $nonce)
			return $this->failure('publish.failure_signature');
		if (empty($this->_config['appid']) || $this->_config['appid'] != $_data['appid'])
			return $this->failure('publish.failure_appid');
		$request_time = local_to_utc(empty($_SERVER['REQUEST_TIME']) ? time() : $_SERVER['REQUEST_TIME']);
		if (($request_time - $_data['timestamp']) > 300) //误差在5分钟以外，不合法
			return $this->failure('publish.failure_signature_time');
		return $_data['data'];
	}

	private function get_local_post_param()
	{
		$ip = $_SERVER['REMOTE_ADDR'];
		if (empty($ip) || !ip_in_subnet('127.0.0.1/24', $ip)) //本机方可访问
			return $this->failure('tools.failure_ip_invail');

		$keys = 'url,secret,encode';
		$data = Validate::instance()->get_post_data($keys,'publish/edit');
		if (!empty($data['error']))
			return $this->failure_post($data['error']);
		extract($data['data']);
		!!$data['data']['encode'] && $data['data']['secret'] = Encrypt::instance()->decode($data['data']['secret']);
		if ($data['data']['secret'] == $this->_config['secret'])
			return $this->failure('publish.failure_secret_eq_to_local');
		return $data['data'];
	}

	public function action_index()
	{
		$ip = $_SERVER['REMOTE_ADDR'];
		if (empty($ip) || !ip_in_subnet('127.0.0.1/24', $ip)) //本机方可修改密码
			return $this->failure('tools.failure_ip_invail');

		$this->template->set_filename('smarty3:system/publish');
	}

	public function action_list()
	{
		$this->checkmethod('POST','publish');

		$data = $this->get_local_post_param();

		$this->template->_data = $data;
		$this->template->set_filename('smarty3:system/publish_list');
	}

	
	public function action_remote_query($method, $file = NULL)
	{
		$data = $this->get_local_post_param();
		$_data = array();

		!empty($file) && $file = Encrypt::instance()->decode(str_replace(' ','+',$file));
		$_data = compact('file');

		$signature = $this->encode_signature($this->_config['appid'], $data['secret'], $_data);
		$data['url'] .= '/'.rawurldecode('remote_'.$method.'_query').'?of=json&nonce='.rawurldecode($signature['nonce']);

		$request = CURL::post($data['url'], $signature['signature']);

		switch ($method) {
			case 'get_files':
				$data = json_decode($request, TRUE);
				if (!empty($data) && $data['result'] == 'success')
				{
					$list = array();
					$list['local'] = $this->model['publish']->get_file_list();
					$list['remote'] = &$data['data'];
					$diff = $this->model['publish']->compare_file_list($list['local'], $list['remote']);
					unset($list);
					$diff = array_delete_selector($diff, '*/*/*/path,uid,gid,mtime,atime,ctime,nlink');
					return $this->success('', FALSE, $diff);
				}
				break;
			case 'get_file':
				$data = json_decode($request, TRUE);
				if (!empty($data) && $data['result'] == 'success')
				{
					$content = array();
					$content['local'] = $this->model['publish']->get_file_content($file);
					$content['remote'] = $data['data']['content'];
					$diff = NULL;
					if ($this->model['publish']->file_type($file) == 'text')
						$diff = empty($content['local']) || empty($content['remote']) ? '' : HTMLDiff::instance()->compare($content['remote'], $content['local']);
							
					return $this->success('', FALSE, compact('diff','file') + $content);
				}
			default:
				
				break;
		}
		echo $request;
	}

	public function action_remote_get_files_query($nonce)
	{
		$this->checkmethod('POST','publish');
		$signature = file_get_contents('php://input');

		$this->verify_signature($this->_config['secret'], $signature, $nonce);

		$list = $this->model['publish']->get_file_list();
		$list = array_delete_selector($list, '*/*/*/path,uid,gid,mtime,atime,ctime,nlink');
					
		return $this->success('', FALSE, $list);
	}

	public function action_remote_get_file_query($nonce)
	{
		$this->checkmethod('POST','publish');
		$signature = file_get_contents('php://input');

		$_data = $this->verify_signature($this->_config['secret'], $signature, $nonce);
		
		$content = $this->model['publish']->get_file_content($_data['file']);
		return $this->success('', FALSE, compact('content'));
		//return $this->failure('publish.failure_file_exists');
	}
}